import { readFile } from 'fs/promises';
import { basename, dirname } from 'path';
import { LibraryFormats, Plugin, ResolvedConfig } from 'vite';

export interface UserScriptOptions {
	entry: string;
	format: LibraryFormats;
	name?: string;
	port?: number;
	cdn?: string;
}

export function _userscript(options: UserScriptOptions): Plugin {
	let config: ResolvedConfig;

	return {
		name: 'userscript',
		config() {
			const name = options.name ?? basename(dirname(options.entry));

			return {
				build: {
					lib: {
						name: name,
						formats: [ options.format ],
						entry: {
							[name]: options.entry
						}
					},
					rollupOptions: {
						output: {
							entryFileNames: '[name].user.js'
						}
					}
				}
			};
		},
		configResolved(resolvedConfig) {
			config = resolvedConfig;
		},
		async generateBundle(outputOptions, bundle) {
			for (const chunk of Object.values(bundle)) {
				if (chunk.type !== 'chunk') continue;
				if (!chunk.isEntry) continue;
				if (!chunk.facadeModuleId) continue;

				const code = await readFile(chunk.facadeModuleId, { encoding: 'utf8' });

				let header = '';
				for (const line of code.split('\n')) {
					if (!line.startsWith('//')) break;
					header += line + '\n';
				}

				let url = '';
				if (config.mode === 'production') {
					if (options.cdn) url = `${options.cdn}${chunk.name}.user.js`;
				} else {
					if (options.port) url = `http://localhost:${options.port}/${chunk.name}.user.js`;
				}

				if (url) {
					header = header.replaceAll(
						'// ==/UserScript==',
						`// @downloadURL ${url}\n` +
						`// @updateURL ${url}\n` +
						'// ==/UserScript=='
					);
				}

				chunk.code = header + '\n' + chunk.code;
			}
		}
	};
}
